package vip.wangwenhao.autoconfigure.aspect;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import lombok.extern.slf4j.Slf4j;
import org.apache.skywalking.apm.toolkit.trace.ActiveSpan;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import vip.wangwenhao.common.util.WebUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 日志增强类 - 打印service层和controller层的入参和出参
 *
 * @author wwh
 * @date 2019年12月20日 12:52
 */

@Aspect
@Configuration
@Slf4j
public class LogAspect {

    @Around("execution(public * *(..)) && @within(org.springframework.stereotype.Service)")
    public Object serviceLog(ProceedingJoinPoint joinPoint) throws Throwable {
        String serviceName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        String params;
        String argsJson;
        try {
            params = jsonFormat(args);
            argsJson = JSONArray.toJSONString(args);
        } catch (Exception e) {
            params = args.toString();
            argsJson = args.toString();
        }
        log.info("{} params={}", serviceName, argsJson);
        ActiveSpan.info(String.format("%s params=\n%s", serviceName, params));
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long end = System.currentTimeMillis();
        log.info("{} time={} result={}", serviceName, end - start, JSONObject.toJSONString(result, SerializerFeature.IgnoreNonFieldGetter));
        ActiveSpan.info(String.format("%s time=%s result=\n%s", serviceName, end - start, jsonFormat(result)));
        return result;
    }

    @Around("execution(public * *(..)) && (@within(org.springframework.web.bind.annotation.RestController) || @within(org.springframework.stereotype.Controller))")
    public Object controllerLog(ProceedingJoinPoint joinPoint) throws Throwable {
        String requestURI = null;
        String method = null;
        String token = null;
        HttpServletResponse response = null;
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (null != attributes) {
            HttpServletRequest request = attributes.getRequest();
            response = attributes.getResponse();
            requestURI = request.getRequestURI();
            method = request.getMethod();
            token = request.getHeader(HttpHeaders.AUTHORIZATION);
        }
        String serviceName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        String params;
        String argsJson;
        try {
            params = jsonFormat(args);
            argsJson = JSONArray.toJSONString(args);
        } catch (Exception e) {
            params = args.toString();
            argsJson = args.toString();
        }
        try {
            log.info("token={} {} {} {} {} params={}", token, requestURI, method, WebUtils.getRemoteIp(), serviceName, argsJson);
            ActiveSpan.info(String.format("token=%s %s %s %s %s params=\n%s",token, requestURI, method, WebUtils.getRemoteIp(), serviceName, params));
            long start = System.currentTimeMillis();
            Object result = joinPoint.proceed();
            long end = System.currentTimeMillis();
            log.info("{} {} {} {} time={} result={}", requestURI, method, WebUtils.getRemoteIp(), serviceName, end - start, JSONObject.toJSONString(result, SerializerFeature.IgnoreNonFieldGetter));
            ActiveSpan.info(String.format("%s %s %s %s time=%s result=\n%s", requestURI, method, WebUtils.getRemoteIp(), serviceName, end - start, jsonFormat(result)));
            return result;
        } finally {
            if (null != response) {
                response.addHeader("sw-trace-id", TraceContext.traceId());
            }
        }

    }

    private String jsonFormat(Object o){
        String pretty = JSON.toJSONString(o, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteDateUseDateFormat);
        return pretty;
    }
}